﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using System.Diagnostics;
using SimpleIR;

namespace InterpreterCore
{
	/// <summary>
	/// This class represents the local state frame for a method call.
	/// </summary>
	internal partial class LocalCallFrame
	{
		/// <summary>
		/// Map from local variables to the home locations they refer to.
		/// </summary>
		private readonly Dictionary<IRVarName, CHomeLocation> m_localvarmap;

		/// <summary>
		/// The local eval stack.
		/// </summary>
		private readonly EvalStack m_evalstack;

		/// <summary>
		/// The id of the block that is currently being executed in the scope
		/// </summary>
		private long m_currentblock;

		/// <summary>
		/// The index of the opcode in the block that is being executed.
		/// </summary>
		private int m_currentop;

		/// <summary>
		/// The method that this frame corresponds to.
		/// </summary>
		internal readonly IRInvokeIdentity MethodIdentity;

		/// <summary>
		/// The method body that is being executed.
		/// </summary>
		internal readonly IRBodyDef MethodBody;

		/// <summary>
		/// The current state of the debugger.
		/// </summary>
		internal DebugState DebugStatus;

		internal LocalCallFrame(DebugState dbg, IRBodyDef bdf)
		{
			this.m_localvarmap = new Dictionary<IRVarName, CHomeLocation>();
			this.m_evalstack = new EvalStack();

			this.m_currentblock = 0;
			this.m_currentop = 0;

			this.MethodIdentity = bdf.InvokeID;
			this.MethodBody = bdf;
			this.DebugStatus = dbg;
		}

		/// <summary>
		/// Clear out of scope variables as needed, and add newly inscope vars.
		/// </summary>
		internal void ClearVarsNotInScopeAddNew(HashSet<IRVarName> inscope, Dictionary<IRVarName, IRType> nametotypemap)
		{
			List<IRVarName> toelim = new List<IRVarName>();
			foreach(IRVarName vn in this.m_localvarmap.Keys)
			{
				if(!inscope.Contains(vn))
					toelim.Add(vn);
			}

			for(int i = 0; i < toelim.Count; ++i)
			{
				MemoryState.FreeHomeLocation(toelim[i], this.m_localvarmap[toelim[i]].Address);

				this.m_localvarmap.Remove(toelim[i]);
			}

			foreach(IRVarName rri in inscope)
			{
				if(!this.m_localvarmap.ContainsKey(rri))
				{
					IRType lvt = nametotypemap[rri];
					CHomeLocation hloc = MemoryState.AllocateHomeLocation(rri, lvt);

					this.m_localvarmap.Add(rri, hloc);
				}
			}
		}

		private LocalCallFrame(IRBodyDef bdf, long block, int opc, EvalStack evstk, Dictionary<IRVarName, CHomeLocation> vmap, DebugState dbgstate)
		{
			this.m_localvarmap = vmap;
			this.m_evalstack = evstk;

			this.m_currentblock = block;
			this.m_currentop = opc;

			this.MethodIdentity = bdf.InvokeID;
			this.MethodBody = bdf;
			this.DebugStatus = dbgstate;
		}

		public override string ToString()
		{
			StringBuilder sb = new StringBuilder(String.Format("{0}::{1} @ Block={2} Opc={3}\n", this.MethodIdentity.DefInClass.BaseTypeName, this.MethodIdentity.InvSig.InvokeName, this.m_currentblock, this.m_currentop));

			sb.Append(this.m_evalstack.ToString());
			sb.Append("\n");

			sb.Append("Vars={");
			bool first = true;
			foreach(KeyValuePair<IRVarName, CHomeLocation> vmp in this.m_localvarmap)
			{
				if(!first)
					sb.Append(", ");
				first = false;

				sb.Append(String.Format("{0} -> {1}", vmp.Key.VarName, vmp.Value.ToString()));
			}
			sb.Append("}\n");
			
			return sb.ToString();
		}

		internal string DebuggerString()
		{
			StringBuilder sb = new StringBuilder(String.Format("{0}::{1} @ Block={2} Opc={3}\n", this.MethodIdentity.DefInClass.BaseTypeName, this.MethodIdentity.InvSig.InvokeName, this.m_currentblock, this.m_currentop));

			sb.Append(this.m_evalstack.DebuggerString());
			sb.Append("\n");

			sb.Append("Vars={");
			bool first = true;
			foreach(KeyValuePair<IRVarName, CHomeLocation> vmp in this.m_localvarmap)
			{
				if(!first)
					sb.Append(", ");
				first = false;

				sb.Append(String.Format("{0} -> {1}", vmp.Key.VarName, vmp.Value.DebuggerString()));
			}
			sb.Append("}\n");
			
			return sb.ToString();
		}

		internal void SerializeForHeapDump(System.IO.TextWriter dumpstr)
		{
			dumpstr.Write(String.Format("Name={0}::{1} InvokeID={2} Block={3} Opc={4}\n", this.MethodIdentity.DefInClass.BaseTypeName, this.MethodIdentity.InvSig.InvokeName, this.MethodIdentity.InvIDStableKey, this.m_currentblock, this.m_currentop));

			this.m_evalstack.SerializeForHeapDump(dumpstr);
			dumpstr.Write("\n");

			dumpstr.Write("Vars={");
			bool first = true;
			foreach(KeyValuePair<IRVarName, CHomeLocation> vmp in this.m_localvarmap)
			{
				if(!first)
					dumpstr.Write(',');
				first = false;

				dumpstr.Write(String.Format("{0}*{1}", vmp.Key.VarName, vmp.Value.Address));
			}
			dumpstr.Write("}\n");
		}

		internal void SerializeForDGMLDisplay(System.Xml.XmlWriter nodexw, System.Xml.XmlWriter edgexw, int acpos)
		{
			string prfx = (acpos != -1) ? String.Format("{0}#{1}::{2}.", acpos, this.MethodIdentity.DefInClass.BaseTypeName, this.MethodIdentity.InvSig.InvokeName) : "";
			this.m_evalstack.SerializeForDGMLDisplay(nodexw, edgexw, prfx);

			foreach(KeyValuePair<IRVarName, CHomeLocation> vmp in this.m_localvarmap)
				vmp.Value.SerializeForDGMLDisplay(nodexw, edgexw, prfx + vmp.Key.VarName);
		}

		internal static LocalCallFrame ParseCallFrame(System.IO.TextReader rdr, DebugState dbgstate)
		{
			string infoline = rdr.ReadLine();
			Dictionary<string, string> ipkvp = TracingSystem.ParseKeyValuePairs(infoline);
			int methodid = Int32.Parse(ipkvp["InvokeID"]);
			IRInvokeIdentity iiv = GlobalInterpreterState.TProg.InvokeTable.GetInvokeWithID(methodid);
			IRBodyDef bdf = GlobalInterpreterState.TProg.MethodBodyTable.GetBodyForInvokeExactSigMatch(iiv);

			long cblock = Int64.Parse(ipkvp["Block"]);
			int opc = Int32.Parse(ipkvp["Opc"]);

			string stackline = rdr.ReadLine();
			Dictionary<string, string> slkvp = TracingSystem.ParseKeyValuePairs(stackline);
			EvalStack evstk = EvalStack.ParseEvalStack(slkvp);

			string varsline = rdr.ReadLine();
			string[] vps = varsline.Substring(6, varsline.Length - 7).Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
			Dictionary<IRVarName, CHomeLocation> localmap = new Dictionary<IRVarName, CHomeLocation>();
			for(int i = 0; i < vps.Length; ++i)
			{
				int ipos = vps[i].IndexOf('*');
				
				string name = vps[i].Substring(0, ipos);
				IRVarName vn = GlobalInterpreterState.TProg.NameTable.LookupLocalVarName(name);

				int address = Int32.Parse(vps[i].Substring(ipos + 1));
				CHomeLocation hloc = (CHomeLocation)MemoryState.ResolveRawAddress(address);

				localmap.Add(vn, hloc);
			}

			return new LocalCallFrame(bdf, cblock, opc, evstk, localmap, dbgstate);
		}

		internal void EmitEvalStackForTraceAtStmtExecute()
		{
			TracingSystem.LogEvalStackValues(this.m_evalstack);
		}

		////////////////////

		internal long CurrentBlock
		{ get { return this.m_currentblock; } }

		internal int CurrentOp
		{ get { return this.m_currentop; } }

		internal bool StackPopBoolBranchValue()
		{ return this.m_evalstack.PopNumericValueAsType(GlobalInterpreterState.TProg.TypeTable.BoolType).ReadSignedValue() != 0; }

		internal int StackPopSwitchValue()
		{ return (int)this.m_evalstack.PopNumericValueAsType(GlobalInterpreterState.TProg.TypeTable.Int32Type).ReadSignedValue(); }

		internal void SetPCToBlockStart(long blockid)
		{
			this.m_currentblock = blockid;
			this.m_currentop = 0;
		}

		/// <summary>
		/// Resolve the location that the pointer is to.
		/// </summary>
		internal static CObject ResolvePointerTarget(PtrValue p)
		{
			if(p.IsNullPtr)
				throw new InterpRuntimeException("Null pointer dereference!");

			return (CObject)MemoryState.ResolveRawAddress_KnownHeap(p.TargetAddress); 
		}

		/// <summary>
		/// Resolve the location that the reference is to.
		/// </summary>
		internal static CLocation ResolveReferenceTarget(ReferenceValue r)
		{
			if(r.IsNullReference)
				throw new InterpRuntimeException("Null reference dereference!");

			return (CObject)MemoryState.ResolveRawAddress(r.TargetAddress); 
		}

		/// <summary>
		/// Add all the addresses reachable from the locals into reachaddr.
		/// </summary>
		internal void WalkAllReachableFromRoots(HashSet<int> reachaddr)
		{
			Queue<int> toproc = new Queue<int>();
			foreach(CHomeLocation chl in this.m_localvarmap.Values)
			{
				toproc.Enqueue(chl.Address);
				reachaddr.Add(chl.Address);
			}

			while(toproc.Count != 0)
			{
				int addr = toproc.Dequeue();
				CLocation ll = MemoryState.ResolveRawAddress(addr);
				
				IEnumerator<int> refenum = ll.EnumerateTrgtAddresses().GetEnumerator();
				while(refenum.MoveNext())
				{
					if(refenum.Current != -1 && !reachaddr.Contains(refenum.Current))
					{
						toproc.Enqueue(refenum.Current);
						reachaddr.Add(refenum.Current);
					}
				}
			}
		}

		//////////////
		//Allocation

		/// <summary>
		/// Simulate the allocation of an object or struct (YOU MUST DO initialization call later if desired).
		/// Note we don't let you alloc raw pointers or blank arrays (because they always need a size parameter).
		/// </summary>
		internal void SimulateAllocBlank(IRType alloctype)
		{
			if(alloctype is IRStructType)
				this.m_evalstack.PushStructEvalEntry((IRStructType)alloctype, CompositeValue.MakeCompositeValue((IRStructType)alloctype));
			else
			{
				//invoke gc
				MemoryState.DoGC();

				IRPtrType drftype = GlobalInterpreterState.TProg.TypeTable.LookupPointerTypeFor((IRClassType)alloctype);
				CObject nloc = MemoryState.AllocateStdHeapObject((IRClassType)alloctype);

				this.m_evalstack.PushPointerEvalEntry(new PtrValue(nloc.Address, drftype));
			}
		}

		/// <summary>
		/// Simulate the allocation of an array.
		/// </summary>
		internal void SimulateAllocArray(IRArrayType alloctype)
		{
			//invoke gc
			MemoryState.DoGC();

			IRPtrType drftype = GlobalInterpreterState.TProg.TypeTable.LookupPointerTypeFor((IRClassType)alloctype);

			NumericValue nv = this.m_evalstack.PopNumericValueAsType(GlobalInterpreterState.TProg.TypeTable.Int32Type);
			CArray nloc = MemoryState.AllocateArrayObject(alloctype, nv);

			this.m_evalstack.PushPointerEvalEntry(new PtrValue(nloc.Address, drftype));
		}

		/// <summary>
		/// Simulate the allocation of a delegate object.
		/// </summary>
		internal void SimulateAllocDelegate(IRLambdaType alloctype)
		{
			//invoke gc
			MemoryState.DoGC();

			IRPtrType drftype = GlobalInterpreterState.TProg.TypeTable.LookupPointerTypeFor((IRClassType)alloctype);

			IRInvokeIdentity inv = this.m_evalstack.PopFunctionPtr();
			CDelegate nloc = MemoryState.AllocateDelegateObject(alloctype, inv);

			this.m_evalstack.PushPointerEvalEntry(new PtrValue(nloc.Address, drftype));
		}

		//////////////
		//Primitive Load/Store

		/// <summary>
		/// Simulate the load of a value from a local variable to the stack.
		/// </summary>
		internal void SimulateLoadFromLocal(IRVarName localv)
		{
			CHomeLocation lvn = this.m_localvarmap[localv];

			if(lvn.LocationType is IRPrimitiveNumericType || lvn.LocationType is IREnumType)
			{
				NumericValue nv = lvn.ReadPassableNumericFromFromHomeLocation();
				this.m_evalstack.PushNumericEvalEntry(nv);
			}
			else if(lvn.LocationType is IRReferenceType)
			{
				ReferenceValue rv = lvn.ReadPassableReferenceValueFromHomeLocation();
				this.m_evalstack.PushReferenceEvalEntry(rv);
			}
			else if(lvn.LocationType is IRPtrType)
			{
				PtrValue pv = lvn.ReadPassablePtrValueFromHomeLocation();
				this.m_evalstack.PushPointerEvalEntry(pv);
			}
			else
			{
				CompositeValueEntry[] cve = lvn.ReadStructFromHomeLocation();
				this.m_evalstack.PushStructEvalEntry((IRStructType)lvn.LocationType, cve);
			}
		}

		/// <summary>
		/// Simulate the store of a value to a local variable from the stack.
		/// </summary>
		internal void SimulateStoreToLocal(IRVarName localv)
		{
			CHomeLocation lvn = this.m_localvarmap[localv];
			IRType sltype = this.m_evalstack.PeekType();

			if(lvn.LocationType is IRPrimitiveNumericType || lvn.LocationType is IREnumType)
			{
				NumericValue nv = this.m_evalstack.PopNumericValueAsType(lvn.LocationType);
				lvn.StorePassableNumericValToHomeLocation(nv);
			}
			else if(lvn.LocationType is IRReferenceType)
			{
				Debug.Assert(GlobalInterpreterState.TProg.IsT1AssignableToT2(sltype, lvn.LocationType));

				ReferenceValue rv = this.m_evalstack.PopReference();
				lvn.StorePassableReferenceValToHomeLocation(rv);
			}
			else if(lvn.LocationType is IRPtrType)
			{
				Debug.Assert(GlobalInterpreterState.TProg.IsT1AssignableToT2(sltype, lvn.LocationType));

				PtrValue pv = this.m_evalstack.PopPointerAsType((IRPtrType)lvn.LocationType);
				lvn.StorePassablePtrValToHomeLocation(pv);
			}
			else
			{
				Debug.Assert(GlobalInterpreterState.TProg.IsT1AssignableToT2(sltype, lvn.LocationType));

				CompositeValueEntry[] cve = this.m_evalstack.PopStruct();
				lvn.StoreCompositeToHomeLocation(cve);
			}
		}

		/// <summary>
		/// Simulate the load of a value from a global variable to the stack.
		/// </summary>
		internal void SimulateLoadFromGlobal(IRStaticField sf, Dictionary<IRStaticField, CHomeLocation> globallocations)
		{
			CHomeLocation sfn = globallocations[sf];

			if(sfn.LocationType is IRPrimitiveNumericType || sfn.LocationType is IREnumType)
			{
				NumericValue nv = sfn.ReadPassableNumericFromFromHomeLocation();
				this.m_evalstack.PushNumericEvalEntry(nv);
			}
			else if(sfn.LocationType is IRPtrType)
			{
				PtrValue pv = sfn.ReadPassablePtrValueFromHomeLocation();
				this.m_evalstack.PushPointerEvalEntry(pv);
			}
			else
			{
				CompositeValueEntry[] cve = sfn.ReadStructFromHomeLocation();
				this.m_evalstack.PushStructEvalEntry((IRStructType)sfn.LocationType, cve);
			}
		}

		/// <summary>
		/// Simulate the store of a value to a global variable from the stack.
		/// </summary>
		internal void SimulateStoreToGlobal(IRStaticField sf, Dictionary<IRStaticField, CHomeLocation> globallocations)
		{
			CHomeLocation sfn = globallocations[sf];
			IRType sltype = this.m_evalstack.PeekType();

			if(sfn.LocationType is IRPrimitiveNumericType || sfn.LocationType is IREnumType)
			{
				NumericValue nv = this.m_evalstack.PopNumericValueAsType(sfn.LocationType);
				sfn.StorePassableNumericValToHomeLocation(nv);
			}
			else if(sfn.LocationType is IRPtrType)
			{
				Debug.Assert(GlobalInterpreterState.TProg.IsT1AssignableToT2(sltype, sfn.LocationType));

				PtrValue pv = this.m_evalstack.PopPointerAsType((IRPtrType)sfn.LocationType);
				sfn.StorePassablePtrValToHomeLocation(pv);
			}
			else
			{
				Debug.Assert(GlobalInterpreterState.TProg.IsT1AssignableToT2(sltype, sfn.LocationType));

				CompositeValueEntry[] cve = this.m_evalstack.PopStruct();
				sfn.StoreCompositeToHomeLocation(cve);
			}
		}

		//////////////
		//Primitive Compare

		/// <summary>
		/// Simulate the equality operation.
		/// </summary>
		internal void SimulatePrimEQ()
		{
			this.m_evalstack.AssertTopTwoEntriesAreSameType();

			IREvalStackPrimitiveType evst = (IREvalStackPrimitiveType)this.m_evalstack.PeekType();
			StackNumericValue v2 = this.m_evalstack.PopRawEvalStackNumeric();
			StackNumericValue v1 = this.m_evalstack.PopRawEvalStackNumeric();

			StackNumericValue res = StackNumericValue.SimulatePrimEQ(v1, v2, evst);
			this.m_evalstack.PushRawStackNumericVal(res, GlobalInterpreterState.TProg.TypeTable.EvalStackInt32Type);
		}

		/// <summary>
		/// Simulate the less operation.
		/// </summary>
		internal void SimulateLess()
		{
			this.m_evalstack.AssertTopTwoEntriesAreSameType();

			IREvalStackPrimitiveType evst = (IREvalStackPrimitiveType)this.m_evalstack.PeekType();
			StackNumericValue v2 = this.m_evalstack.PopRawEvalStackNumeric();
			StackNumericValue v1 = this.m_evalstack.PopRawEvalStackNumeric();

			StackNumericValue res = StackNumericValue.SimulateLess(v1, v2, evst);
			this.m_evalstack.PushRawStackNumericVal(res, GlobalInterpreterState.TProg.TypeTable.EvalStackInt32Type);
		}

		/// <summary>
		/// Simulate the less operation (unsigned).
		/// </summary>
		internal void SimulateLessUnsigned()
		{
			this.m_evalstack.AssertTopTwoEntriesAreSameType();

			IREvalStackPrimitiveType evst = (IREvalStackPrimitiveType)this.m_evalstack.PeekType();
			StackNumericValue v2 = this.m_evalstack.PopRawEvalStackNumeric();
			StackNumericValue v1 = this.m_evalstack.PopRawEvalStackNumeric();

			StackNumericValue res = StackNumericValue.SimulateLessUnsigned(v1, v2, evst);
			this.m_evalstack.PushRawStackNumericVal(res, GlobalInterpreterState.TProg.TypeTable.EvalStackInt32Type);
		}

		/// <summary>
		/// Simulate the less than or equal operation.
		/// </summary>
		internal void SimulateLessEQ()
		{
			this.m_evalstack.AssertTopTwoEntriesAreSameType();

			IREvalStackPrimitiveType evst = (IREvalStackPrimitiveType)this.m_evalstack.PeekType();
			StackNumericValue v2 = this.m_evalstack.PopRawEvalStackNumeric();
			StackNumericValue v1 = this.m_evalstack.PopRawEvalStackNumeric();

			StackNumericValue res = StackNumericValue.SimulateLessEQ(v1, v2, evst);
			this.m_evalstack.PushRawStackNumericVal(res, GlobalInterpreterState.TProg.TypeTable.EvalStackInt32Type);
		}

		/// <summary>
		/// Simulate the less than or equal operation (unsigned).
		/// </summary>
		internal void SimulateLessEQUnsigned()
		{
			this.m_evalstack.AssertTopTwoEntriesAreSameType();

			IREvalStackPrimitiveType evst = (IREvalStackPrimitiveType)this.m_evalstack.PeekType();
			StackNumericValue v2 = this.m_evalstack.PopRawEvalStackNumeric();
			StackNumericValue v1 = this.m_evalstack.PopRawEvalStackNumeric();

			StackNumericValue res = StackNumericValue.SimulateLessEQUnsigned(v1, v2, evst);
			this.m_evalstack.PushRawStackNumericVal(res, GlobalInterpreterState.TProg.TypeTable.EvalStackInt32Type);
		}

		/// <summary>
		/// Simulate the greater operation.
		/// </summary>
		internal void SimulateGreater()
		{
			this.m_evalstack.AssertTopTwoEntriesAreSameType();

			IREvalStackPrimitiveType evst = (IREvalStackPrimitiveType)this.m_evalstack.PeekType();
			StackNumericValue v2 = this.m_evalstack.PopRawEvalStackNumeric();
			StackNumericValue v1 = this.m_evalstack.PopRawEvalStackNumeric();

			StackNumericValue res = StackNumericValue.SimulateGreater(v1, v2, evst);
			this.m_evalstack.PushRawStackNumericVal(res, GlobalInterpreterState.TProg.TypeTable.EvalStackInt32Type);
		}

		/// <summary>
		/// Simulate the greater operation (unsigned).
		/// </summary>
		internal void SimulateGreaterUnsigned()
		{
			this.m_evalstack.AssertTopTwoEntriesAreSameType();

			IREvalStackPrimitiveType evst = (IREvalStackPrimitiveType)this.m_evalstack.PeekType();
			StackNumericValue v2 = this.m_evalstack.PopRawEvalStackNumeric();
			StackNumericValue v1 = this.m_evalstack.PopRawEvalStackNumeric();

			StackNumericValue res = StackNumericValue.SimulateGreaterUnsigned(v1, v2, evst);
			this.m_evalstack.PushRawStackNumericVal(res, GlobalInterpreterState.TProg.TypeTable.EvalStackInt32Type);
		}

		/// <summary>
		/// Simulate the greater than or equal operation.
		/// </summary>
		internal void SimulateGreaterEQ()
		{
			this.m_evalstack.AssertTopTwoEntriesAreSameType();

			IREvalStackPrimitiveType evst = (IREvalStackPrimitiveType)this.m_evalstack.PeekType();
			StackNumericValue v2 = this.m_evalstack.PopRawEvalStackNumeric();
			StackNumericValue v1 = this.m_evalstack.PopRawEvalStackNumeric();

			StackNumericValue res = StackNumericValue.SimulateGreaterEQ(v1, v2, evst);
			this.m_evalstack.PushRawStackNumericVal(res, GlobalInterpreterState.TProg.TypeTable.EvalStackInt32Type);
		}

		/// <summary>
		/// Simulate the greater than or equal operation (unsigned).
		/// </summary>
		internal void SimulateGreaterEQUnsigned()
		{
			this.m_evalstack.AssertTopTwoEntriesAreSameType();

			IREvalStackPrimitiveType evst = (IREvalStackPrimitiveType)this.m_evalstack.PeekType();
			StackNumericValue v2 = this.m_evalstack.PopRawEvalStackNumeric();
			StackNumericValue v1 = this.m_evalstack.PopRawEvalStackNumeric();

			StackNumericValue res = StackNumericValue.SimulateGreaterEQUnsigned(v1, v2, evst);
			this.m_evalstack.PushRawStackNumericVal(res, GlobalInterpreterState.TProg.TypeTable.EvalStackInt32Type);
		}
		
		//////////////
		//Primitive Arith Operations

		/// <summary>
		/// Simulate an add operation.
		/// </summary>
		internal void SimulateAdd()
		{
			this.m_evalstack.AssertTopTwoEntriesAreSameType();

			IREvalStackPrimitiveType evst = (IREvalStackPrimitiveType)this.m_evalstack.PeekType();
			StackNumericValue v2 = this.m_evalstack.PopRawEvalStackNumeric();
			StackNumericValue v1 = this.m_evalstack.PopRawEvalStackNumeric();

			StackNumericValue res = StackNumericValue.SimulateAdd(v1, v2, evst);
			this.m_evalstack.PushRawStackNumericVal(res, evst);
		}

		/// <summary>
		/// Simulate an add operation (unsigned).
		/// </summary>
		internal void SimulateAddUnsigned()
		{
			this.m_evalstack.AssertTopTwoEntriesAreSameType();

			IREvalStackPrimitiveType evst = (IREvalStackPrimitiveType)this.m_evalstack.PeekType();
			StackNumericValue v2 = this.m_evalstack.PopRawEvalStackNumeric();
			StackNumericValue v1 = this.m_evalstack.PopRawEvalStackNumeric();

			StackNumericValue res = StackNumericValue.SimulateAddUnsigned(v1, v2, evst);
			this.m_evalstack.PushRawStackNumericVal(res, evst);
		}

		/// <summary>
		/// Simulate a divide operation.
		/// </summary>
		internal void SimulateDiv()
		{
			this.m_evalstack.AssertTopTwoEntriesAreSameType();

			IREvalStackPrimitiveType evst = (IREvalStackPrimitiveType)this.m_evalstack.PeekType();
			StackNumericValue v2 = this.m_evalstack.PopRawEvalStackNumeric();
			StackNumericValue v1 = this.m_evalstack.PopRawEvalStackNumeric();

			StackNumericValue res = StackNumericValue.SimulateDiv(v1, v2, evst);
			this.m_evalstack.PushRawStackNumericVal(res, evst);
		}

		/// <summary>
		/// Simulate an divide operation (unsigned).
		/// </summary>
		internal void SimulateDivUnsigned()
		{
			this.m_evalstack.AssertTopTwoEntriesAreSameType();

			IREvalStackPrimitiveType evst = (IREvalStackPrimitiveType)this.m_evalstack.PeekType();
			StackNumericValue v2 = this.m_evalstack.PopRawEvalStackNumeric();
			StackNumericValue v1 = this.m_evalstack.PopRawEvalStackNumeric();

			StackNumericValue res = StackNumericValue.SimulateDivUnsigned(v1, v2, evst);
			this.m_evalstack.PushRawStackNumericVal(res, evst);
		}

		/// <summary>
		/// Simulate a multiply operation.
		/// </summary>
		internal void SimulateMult()
		{
			this.m_evalstack.AssertTopTwoEntriesAreSameType();

			IREvalStackPrimitiveType evst = (IREvalStackPrimitiveType)this.m_evalstack.PeekType();
			StackNumericValue v2 = this.m_evalstack.PopRawEvalStackNumeric();
			StackNumericValue v1 = this.m_evalstack.PopRawEvalStackNumeric();

			StackNumericValue res = StackNumericValue.SimulateMult(v1, v2, evst);
			this.m_evalstack.PushRawStackNumericVal(res, evst);
		}

		/// <summary>
		/// Simulate a multiply operation (unsigned).
		/// </summary>
		internal void SimulateMultUnsigned()
		{
			this.m_evalstack.AssertTopTwoEntriesAreSameType();

			IREvalStackPrimitiveType evst = (IREvalStackPrimitiveType)this.m_evalstack.PeekType();
			StackNumericValue v2 = this.m_evalstack.PopRawEvalStackNumeric();
			StackNumericValue v1 = this.m_evalstack.PopRawEvalStackNumeric();

			StackNumericValue res = StackNumericValue.SimulateMultUnsigned(v1, v2, evst);
			this.m_evalstack.PushRawStackNumericVal(res, evst);
		}

		/// <summary>
		/// Simulate a negate operation.
		/// </summary>
		internal void SimulateNeg()
		{
			IREvalStackPrimitiveType evst = (IREvalStackPrimitiveType)this.m_evalstack.PeekType();
			StackNumericValue v = this.m_evalstack.PopRawEvalStackNumeric();

			StackNumericValue res = StackNumericValue.SimulateNeg(v, evst);
			this.m_evalstack.PushRawStackNumericVal(res, evst);
		}

		/// <summary>
		/// Simulate a remainder operation.
		/// </summary>
		internal void SimulateRem()
		{
			this.m_evalstack.AssertTopTwoEntriesAreSameType();

			IREvalStackPrimitiveType evst = (IREvalStackPrimitiveType)this.m_evalstack.PeekType();
			StackNumericValue v2 = this.m_evalstack.PopRawEvalStackNumeric();
			StackNumericValue v1 = this.m_evalstack.PopRawEvalStackNumeric();

			StackNumericValue res = StackNumericValue.SimulateRem(v1, v2, evst);
			this.m_evalstack.PushRawStackNumericVal(res, evst);
		}

		/// <summary>
		/// Simulate a remainder operation (unsigned).
		/// </summary>
		internal void SimulateRemUnsigned()
		{
			this.m_evalstack.AssertTopTwoEntriesAreSameType();

			IREvalStackPrimitiveType evst = (IREvalStackPrimitiveType)this.m_evalstack.PeekType();
			StackNumericValue v2 = this.m_evalstack.PopRawEvalStackNumeric();
			StackNumericValue v1 = this.m_evalstack.PopRawEvalStackNumeric();

			StackNumericValue res = StackNumericValue.SimulateRemUnsigned(v1, v2, evst);
			this.m_evalstack.PushRawStackNumericVal(res, evst);
		}

		/// <summary>
		/// Simulate a subtract operation.
		/// </summary>
		internal void SimulateSub()
		{
			this.m_evalstack.AssertTopTwoEntriesAreSameType();

			IREvalStackPrimitiveType evst = (IREvalStackPrimitiveType)this.m_evalstack.PeekType();
			StackNumericValue v2 = this.m_evalstack.PopRawEvalStackNumeric();
			StackNumericValue v1 = this.m_evalstack.PopRawEvalStackNumeric();

			StackNumericValue res = StackNumericValue.SimulateSub(v1, v2, evst);
			this.m_evalstack.PushRawStackNumericVal(res, evst);
		}

		/// <summary>
		/// Simulate a subtract operation (unsigned).
		/// </summary>
		internal void SimulateSubUnsigned()
		{
			this.m_evalstack.AssertTopTwoEntriesAreSameType();

			IREvalStackPrimitiveType evst = (IREvalStackPrimitiveType)this.m_evalstack.PeekType();
			StackNumericValue v2 = this.m_evalstack.PopRawEvalStackNumeric();
			StackNumericValue v1 = this.m_evalstack.PopRawEvalStackNumeric();

			StackNumericValue res = StackNumericValue.SimulateSubUnsigned(v1, v2, evst);
			this.m_evalstack.PushRawStackNumericVal(res, evst);
		}

		//////////////
		//Primitive Bitwise Operations

		/// <summary>
		/// Simulate an and operation.
		/// </summary>
		internal void SimulateAnd()
		{
			this.m_evalstack.AssertTopTwoEntriesAreSameType();

			IREvalStackPrimitiveType evst = (IREvalStackPrimitiveType)this.m_evalstack.PeekType();
			StackNumericValue v2 = this.m_evalstack.PopRawEvalStackNumeric();
			StackNumericValue v1 = this.m_evalstack.PopRawEvalStackNumeric();

			StackNumericValue res = StackNumericValue.SimulateAnd(v1, v2, evst);
			this.m_evalstack.PushRawStackNumericVal(res, evst);
		}

		/// <summary>
		/// Simulate an or operation.
		/// </summary>
		internal void SimulateOr()
		{
			this.m_evalstack.AssertTopTwoEntriesAreSameType();

			IREvalStackPrimitiveType evst = (IREvalStackPrimitiveType)this.m_evalstack.PeekType();
			StackNumericValue v2 = this.m_evalstack.PopRawEvalStackNumeric();
			StackNumericValue v1 = this.m_evalstack.PopRawEvalStackNumeric();

			StackNumericValue res = StackNumericValue.SimulateOr(v1, v2, evst);
			this.m_evalstack.PushRawStackNumericVal(res, evst);
		}

		/// <summary>
		/// Simulate a not operation.
		/// </summary>
		internal void SimulateNot()
		{
			IREvalStackPrimitiveType evst = (IREvalStackPrimitiveType)this.m_evalstack.PeekType();
			StackNumericValue v = this.m_evalstack.PopRawEvalStackNumeric();
			
			StackNumericValue res = StackNumericValue.SimulateNot(v, evst);
			this.m_evalstack.PushRawStackNumericVal(res, evst);
		}

		/// <summary>
		/// Simulate a shl operation.
		/// </summary>
		internal void SimulateShl()
		{
			this.m_evalstack.AssertTopTwoEntriesAreSameType();

			IREvalStackPrimitiveType evst = (IREvalStackPrimitiveType)this.m_evalstack.PeekType();
			StackNumericValue v2 = this.m_evalstack.PopRawEvalStackNumeric();
			StackNumericValue v1 = this.m_evalstack.PopRawEvalStackNumeric();

			StackNumericValue res = StackNumericValue.SimulateShl(v1, v2, evst);
			this.m_evalstack.PushRawStackNumericVal(res, evst);
		}

		/// <summary>
		/// Simulate a shr operation.
		/// </summary>
		internal void SimulateShr()
		{
			this.m_evalstack.AssertTopTwoEntriesAreSameType();

			IREvalStackPrimitiveType evst = (IREvalStackPrimitiveType)this.m_evalstack.PeekType();
			StackNumericValue v2 = this.m_evalstack.PopRawEvalStackNumeric();
			StackNumericValue v1 = this.m_evalstack.PopRawEvalStackNumeric();

			StackNumericValue res = StackNumericValue.SimulateShr(v1, v2, evst);
			this.m_evalstack.PushRawStackNumericVal(res, evst);
		}

		/// <summary>
		/// Simulate a shr operation (unsigned).
		/// </summary>
		internal void SimulateShrUnsigned()
		{
			this.m_evalstack.AssertTopTwoEntriesAreSameType();

			IREvalStackPrimitiveType evst = (IREvalStackPrimitiveType)this.m_evalstack.PeekType();
			StackNumericValue v2 = this.m_evalstack.PopRawEvalStackNumeric();
			StackNumericValue v1 = this.m_evalstack.PopRawEvalStackNumeric();

			StackNumericValue res = StackNumericValue.SimulateShrUnsigned(v1, v2, evst);
			this.m_evalstack.PushRawStackNumericVal(res, evst);
		}

		/// <summary>
		/// Simulate an xor operation.
		/// </summary>
		internal void SimulateXor()
		{
			this.m_evalstack.AssertTopTwoEntriesAreSameType();

			IREvalStackPrimitiveType evst = (IREvalStackPrimitiveType)this.m_evalstack.PeekType();
			StackNumericValue v2 = this.m_evalstack.PopRawEvalStackNumeric();
			StackNumericValue v1 = this.m_evalstack.PopRawEvalStackNumeric();

			StackNumericValue res = StackNumericValue.SimulateXor(v1, v2, evst);
			this.m_evalstack.PushRawStackNumericVal(res, evst);
		}

		/// <summary>
		/// Analyze a conversion of one primitive type to another.
		/// </summary>
		internal void SimulateConv(IRPrimitiveNumericType cto)
		{
			IREvalStackPrimitiveType evst = (IREvalStackPrimitiveType)this.m_evalstack.PeekType();
			StackNumericValue v = this.m_evalstack.PopRawEvalStackNumeric();

			NumericValue res = v.ConvertToNumericValue_Signed(cto, evst);
			this.m_evalstack.PushNumericEvalEntry(res);
		}

		/// <summary>
		/// Analyze a conversion of one primitive type to another (unsigned).
		/// </summary>
		internal void SimulateConvUnsigned(IRPrimitiveNumericType cto)
		{
			IREvalStackPrimitiveType evst = (IREvalStackPrimitiveType)this.m_evalstack.PeekType();
			StackNumericValue v = this.m_evalstack.PopRawEvalStackNumeric();

			NumericValue res = v.ConvertToNumericValue_UnSigned(cto, evst);
			this.m_evalstack.PushNumericEvalEntry(res);
		}

		//////////////
		//Load/Store Through References

		/// <summary>
		/// Read the array length.
		/// </summary>
		internal void SimulateArrayLength()
		{
			Debug.Assert(this.m_evalstack.PeekType() is IRPtrType);
			PtrValue pval = this.m_evalstack.PopPointerNoTypeConvert();

			CArray arr = (CArray)ResolvePointerTarget(pval);
			NumericValue nv = arr.ReadArrayLength();

			this.m_evalstack.PushNumericEvalEntry(nv);
		}

		/// <summary>
		/// Read a value from the array.
		/// </summary>
		internal void SimulateArrayRead(IRType loadtype)
		{
			Debug.Assert(this.m_evalstack.PeekType() is IREvalStackTypeInt32);
			NumericValue aindex = this.m_evalstack.PopNumericValueAsType(GlobalInterpreterState.TProg.TypeTable.Int32Type);

			Debug.Assert(this.m_evalstack.PeekType() is IRPtrType);
			PtrValue pval = this.m_evalstack.PopPointerNoTypeConvert();

			CArray arr = (CArray)ResolvePointerTarget(pval);
			IRType conttype = ((IRArrayType)arr.LocationType).ArrayContentsType;
			Debug.Assert(loadtype == conttype, "We may need to generalize this.");

			if(loadtype is IRPrimitiveNumericType || loadtype is IREnumType)
			{
				NumericValue nv = arr.ReadPassableNumericFromIndex(aindex);
				this.m_evalstack.PushNumericEvalEntry(nv);
			}
			else if(loadtype is IRPtrType)
			{
				PtrValue pv = arr.ReadPassablePtrValueFromIndex(aindex);
				this.m_evalstack.PushPointerEvalEntry(pv);
			}
			else
			{
				CompositeValueEntry[] cve = arr.ReadCompositeFromIndex(aindex);
				this.m_evalstack.PushStructEvalEntry((IRStructType)loadtype, cve);
			}
		}

		/// <summary>
		/// Store a value into the array.
		/// </summary>
		internal void SimulateArrayStore(IRType storetype)
		{
			NumericValue nv = NumericValue.MakeZeroValueOfType(null);
			PtrValue pv = PtrValue.MakeNullPtr(null); 
			CompositeValueEntry[] cve = null;

			IRType vtype = this.m_evalstack.PeekType();
			if(storetype is IRPrimitiveNumericType || storetype is IREnumType)
				nv = this.m_evalstack.PopNumericValueAsType(storetype);
			else if(storetype is IRPtrType)
			{
				Debug.Assert(GlobalInterpreterState.TProg.IsT1AssignableToT2(vtype, storetype));
				pv = this.m_evalstack.PopPointerAsType((IRPtrType)storetype);
			}
			else
			{
				Debug.Assert(GlobalInterpreterState.TProg.IsT1AssignableToT2(vtype, storetype));
				cve = this.m_evalstack.PopStruct();
			}

			Debug.Assert(this.m_evalstack.PeekType() is IREvalStackTypeInt32);
			NumericValue aindex = this.m_evalstack.PopNumericValueAsType(GlobalInterpreterState.TProg.TypeTable.Int32Type);
			
			Debug.Assert(this.m_evalstack.PeekType() is IRPtrType);
			PtrValue pval = this.m_evalstack.PopPointerNoTypeConvert();

			CArray arr = (CArray)ResolvePointerTarget(pval);
			IRType conttype = ((IRArrayType)arr.LocationType).ArrayContentsType;
			Debug.Assert(storetype == conttype, "We may need to generalize this.");

			if(storetype is IRPrimitiveNumericType || storetype is IREnumType)
				arr.StorePassableNumericValToIndex(nv, aindex);
			else if(storetype is IRPtrType)
				arr.StorePassablePtrValToIndex(pv, aindex);
			else
				arr.StoreCompositeToIndex(cve, aindex);
		}

		/// <summary>
		/// Read a value through the Reference.
		/// </summary>
		internal void SimulateDeRefIndirectRead()
		{
			Debug.Assert(this.m_evalstack.PeekType() is IRReferenceType);
			IRType loadtype = ((IRReferenceType)this.m_evalstack.PeekType()).ReferenceTargetType;
			ReferenceValue rval = this.m_evalstack.PopReference();

			CLocation mloc = ResolveReferenceTarget(rval);

			if(loadtype is IRPrimitiveNumericType || loadtype is IREnumType)
			{
				NumericValue nv = mloc.ReadPassableNumericFrom(rval);
				this.m_evalstack.PushNumericEvalEntry(nv);
			}
			else if(loadtype is IRPtrType)
			{
				PtrValue pv = mloc.ReadPassablePtrValueFrom(rval);
				this.m_evalstack.PushPointerEvalEntry(pv);
			}
			else
			{
				CompositeValueEntry[] cve = mloc.ReadCompositeFrom(rval);
				this.m_evalstack.PushStructEvalEntry((IRStructType)loadtype, cve);
			}
		}

		/// <summary>
		/// Store a value through the reference.
		/// </summary>
		internal void SimulateDeRefIndirectWrite()
		{
			NumericValue nv = NumericValue.MakeZeroValueOfType(null);
			PtrValue pv = PtrValue.MakeNullPtr(null);
			CompositeValueEntry[] cve = null;

			IRType vtype = this.m_evalstack.PeekType();

			Debug.Assert(this.m_evalstack.PeekTypeK(1) is IRReferenceType);
			IRType storetype = ((IRReferenceType)this.m_evalstack.PeekTypeK(1)).ReferenceTargetType;

			if(storetype is IRPrimitiveNumericType || storetype is IREnumType)
				nv = this.m_evalstack.PopNumericValueAsType((IRPrimitiveNumericType)storetype);
			else if(storetype is IRPtrType)
			{
				Debug.Assert(GlobalInterpreterState.TProg.IsT1AssignableToT2(vtype, storetype));
				pv = this.m_evalstack.PopPointerAsType((IRPtrType)storetype);
			}
			else
			{
				Debug.Assert(GlobalInterpreterState.TProg.IsT1AssignableToT2(vtype, storetype));
				cve = this.m_evalstack.PopStruct();
			}

			Debug.Assert(this.m_evalstack.PeekType() is IRReferenceType);
			ReferenceValue rval = this.m_evalstack.PopReference();

			CLocation mloc = ResolveReferenceTarget(rval);

			if(storetype is IRPrimitiveNumericType || storetype is IREnumType)
				mloc.StorePassableNumericValTo(nv, rval);
			else if(storetype is IRPtrType)
				mloc.StorePassablePtrValTo(pv, rval);
			else
				mloc.StoreCompositeTo(cve, rval);
		}

		/// <summary>
		/// Initialize a struct/class value through the reference.
		/// </summary>
		internal void SimulateDeRefIndirectInitialize(IRType toinit)
		{
			Debug.Assert(this.m_evalstack.PeekType() is IRReferenceType);
			Debug.Assert(((IRReferenceType)this.m_evalstack.PeekType()).ReferenceTargetType == toinit);

			ReferenceValue rval = this.m_evalstack.PopReference();
			CLocation mloc = ResolveReferenceTarget(rval);

			if(toinit is IRPrimitiveNumericType || toinit is IREnumType)
			{
				if(toinit is IREnumType)
					toinit = ((IREnumType)toinit).UnerlyingNumericType;

				NumericValue nv = NumericValue.MakeZeroValueOfType((IRPrimitiveNumericType)toinit);
				mloc.StorePassableNumericValTo(nv, rval);
			}
			else if(toinit is IRPtrType)
			{
				PtrValue pv = PtrValue.MakeNullPtr((IRPtrType)toinit);
				mloc.StorePassablePtrValTo(pv, rval);
			}
			else
			{
				CompositeValueEntry[] cve = CompositeValue.MakeCompositeValue((IRStructType)toinit);
				CompositeValue.InitializeToZeroValues(cve);
				mloc.StoreCompositeTo(cve, rval);
			}
		}

		/// <summary>
		/// Do a load from a struct on the evaluation stack.
		/// </summary>
		internal void SimulateReadFromStructOnStack(IRMemberField mf)
		{
			Debug.Assert(this.m_evalstack.PeekType() is IRStructType);

			IRType roottype = this.m_evalstack.PeekType();
			CompositeValueEntry[] cve = this.m_evalstack.PopStruct();

			IRType trgttype = mf.FieldType;
			IRBasicAccessPath mfp = GlobalInterpreterState.TProg.GetAccessPathForSingleField(mf);

			if(trgttype is IRPrimitiveNumericType || trgttype is IREnumType)
			{
				NumericValue nv = CompositeValue.ReadPassableNumericFrom(mfp, cve);
				this.m_evalstack.PushNumericEvalEntry(nv);
			}
			else if(trgttype is IRPtrType)
			{
				PtrValue pv = CompositeValue.ReadPassablePtrValueFrom(mfp, cve);
				this.m_evalstack.PushPointerEvalEntry(pv);
			}
			else
			{
				CompositeValueEntry[] ncve = CompositeValue.ReadCompositeFrom(mfp, cve, roottype);
				this.m_evalstack.PushStructEvalEntry((IRStructType)trgttype, ncve);
			}
		}

		//////////////
		//Pointer Creation and Indexing

		/// <summary>
		/// Load the address of a local variable.
		/// </summary>
		internal void SimulateLoadLocalAddr(IRVarName rv)
		{
			CHomeLocation lhv = this.m_localvarmap[rv];
			IRReferenceType reftype = GlobalInterpreterState.TProg.TypeTable.LookupReferenceTypeFor(lhv.LocationType);
			ReferenceValue erv = new ReferenceValue(lhv.Address, IRBasicAccessPath.EmptyAccessPath, -1, reftype);

			this.m_evalstack.PushReferenceEvalEntry(erv);
		}

		/// <summary>
		/// Load the address of a global address.
		/// </summary>
		internal void SimulateLoadGlobalAddr(IRStaticField sf, Dictionary<IRStaticField, CHomeLocation> globalsmap)
		{
			CHomeLocation lhv = globalsmap[sf];
			IRReferenceType reftype = GlobalInterpreterState.TProg.TypeTable.LookupReferenceTypeFor(lhv.LocationType);
			ReferenceValue erv = new ReferenceValue(lhv.Address, IRBasicAccessPath.EmptyAccessPath, -1, reftype);

			this.m_evalstack.PushReferenceEvalEntry(erv);
		}

		/// <summary>
		/// Index a pointer/reference by the given member field.
		/// </summary>
		internal void SimulateIndexAddrByField(IRMemberField mf, int stackoffset)
		{
			Debug.Assert(this.m_evalstack.PeekTypeK(stackoffset) is IRPtrType || this.m_evalstack.PeekTypeK(stackoffset) is IRReferenceType);

			if(stackoffset != 0)
				this.m_evalstack.DupPositionToTop(stackoffset);

			if(this.m_evalstack.PeekType() is IRPtrType)
			{
				PtrValue pv = this.m_evalstack.PopPointerNoTypeConvert();
				Debug.Assert(!pv.IsNullPtr);

				IRBasicAccessPath rbap = GlobalInterpreterState.TProg.GetAccessPathForSingleField(mf);
				IRReferenceType rt = GlobalInterpreterState.TProg.TypeTable.LookupReferenceTypeFor(mf.FieldType);
				ReferenceValue rv = new ReferenceValue(pv.TargetAddress, rbap, -1, rt);

				this.m_evalstack.PushReferenceEvalEntry(rv);
			}
			else
			{
				ReferenceValue rv = this.m_evalstack.PopReference();
				Debug.Assert(!rv.IsNullReference);

				IRBasicAccessPath rbap = GlobalInterpreterState.TProg.GetAccessPathExtensionPost(rv.TargetOffset, mf);
				IRReferenceType rt = GlobalInterpreterState.TProg.TypeTable.LookupReferenceTypeFor(mf.FieldType);
				ReferenceValue nrv = new ReferenceValue(rv.TargetAddress, rbap, rv.OptArrayIndex, rt);

				this.m_evalstack.PushReferenceEvalEntry(nrv);
			}

			if(stackoffset != 0)
				this.m_evalstack.RotateTopToPosition(stackoffset);
		}

		/// <summary>
		/// Index a pointer by the given array index (mf is the array contents field).
		/// </summary>
		internal void SimulateIndexAddrInsideArray(IRMemberField mf)
		{
			Debug.Assert(this.m_evalstack.PeekType() is IREvalStackTypeInt32);
			Debug.Assert(this.m_evalstack.PeekTypeK(1) is IRPtrType);
			Debug.Assert(((IRPtrType)this.m_evalstack.PeekTypeK(1)).PtrTargetType is IRArrayType);

			int indexv = (int)this.m_evalstack.PopNumericValueAsType(GlobalInterpreterState.TProg.TypeTable.Int32Type).ReadSignedValue();

			PtrValue pv = this.m_evalstack.PopPointerNoTypeConvert();
			Debug.Assert(!pv.IsNullPtr);

			IRBasicAccessPath rbap = GlobalInterpreterState.TProg.GetAccessPathForSingleField(mf);
			IRReferenceType rt = GlobalInterpreterState.TProg.TypeTable.LookupReferenceTypeFor(mf.FieldType);
			ReferenceValue rv = new ReferenceValue(pv.TargetAddress, rbap, indexv, rt);

			this.m_evalstack.PushReferenceEvalEntry(rv);
		}

		/// <summary>
		/// Simulate the load of a known function pointer to the stack.
		/// </summary>
		internal void SimulateLoadFuncPtr(IRInvokeIdentity invid)
		{
			this.m_evalstack.PushFunctionPtrEvalEntry(GlobalInterpreterState.TProg.TypeTable.FunctionPtrType, invid);
		}

		/// <summary>
		/// Read a value through a member field of an object.
		/// </summary>
		internal void SimulateObjectFieldLoad(IRMemberField mf)
		{
			Debug.Assert(this.m_evalstack.PeekType() is IRPtrType);
			IRType loadtype = mf.FieldType;
			PtrValue pval = this.m_evalstack.PopPointerNoTypeConvert();

			CObject oloc = ResolvePointerTarget(pval);

			if(loadtype is IRPrimitiveNumericType || loadtype is IREnumType)
			{
				NumericValue nv = oloc.ReadPassableNumericFromField(mf);
				this.m_evalstack.PushNumericEvalEntry(nv);
			}
			else if(loadtype is IRPtrType)
			{
				PtrValue pv = oloc.ReadPassablePtrValueFromField(mf);
				this.m_evalstack.PushPointerEvalEntry(pv);
			}
			else
			{
				CompositeValueEntry[] cve = oloc.ReadCompositeFromField(mf);
				this.m_evalstack.PushStructEvalEntry((IRStructType)loadtype, cve);
			}
		}

		/// <summary>
		/// Store a value through an object field.
		/// </summary>
		internal void SimulateObjectFieldWrite(IRMemberField mf)
		{
			NumericValue nv = NumericValue.MakeZeroValueOfType(null);
			PtrValue pv = PtrValue.MakeNullPtr(null);
			CompositeValueEntry[] cve = null;

			IRType vtype = this.m_evalstack.PeekType();
			IRType storetype = mf.FieldType;

			if(storetype is IRPrimitiveNumericType || storetype is IREnumType)
				nv = this.m_evalstack.PopNumericValueAsType(storetype);
			else if(storetype is IRPtrType)
			{
				Debug.Assert(GlobalInterpreterState.TProg.IsT1AssignableToT2(vtype, storetype));
				pv = this.m_evalstack.PopPointerAsType((IRPtrType)storetype);
			}
			else
			{
				Debug.Assert(GlobalInterpreterState.TProg.IsT1AssignableToT2(vtype, storetype));
				cve = this.m_evalstack.PopStruct();
			}

			Debug.Assert(this.m_evalstack.PeekType() is IRPtrType);
			PtrValue pval = this.m_evalstack.PopPointerNoTypeConvert();

			CObject oloc = ResolvePointerTarget(pval);

			if(storetype is IRPrimitiveNumericType || storetype is IREnumType)
				oloc.StorePassableNumericValToField(nv, mf);
			else if(storetype is IRPtrType)
				oloc.StorePassablePtrValToField(pv, mf);
			else
				oloc.StoreCompositeToField(cve, mf);
		}

		//////////////
		//Pointer Compare

		/// <summary>
		/// Equality of the references or pointers on top of the stack.
		/// </summary>
		internal void SimulateDrefableEQ()
		{
			IRType tt = this.m_evalstack.PeekType();

			if(tt is IRPtrType)
			{
				PtrValue p1 = this.m_evalstack.PopPointerNoTypeConvert();
				PtrValue p2 = this.m_evalstack.PopPointerNoTypeConvert();

				int eq = (p1.TargetAddress == p2.TargetAddress) ? 1 : 0;
				NumericValue nv = NumericValue.MakeSignedValueOfType(eq, GlobalInterpreterState.TProg.TypeTable.Int32Type);
				this.m_evalstack.PushNumericEvalEntry(nv);
			}
			else
			{
				ReferenceValue r1 = this.m_evalstack.PopReference();
				ReferenceValue r2 = this.m_evalstack.PopReference();

				int eq = ReferenceValue.AreRefTargetsEqual(r1, r2) ? 1 : 0;
				NumericValue nv = NumericValue.MakeSignedValueOfType(eq, GlobalInterpreterState.TProg.TypeTable.Int32Type);
				this.m_evalstack.PushNumericEvalEntry(nv);
			}
		}

		/// <summary>
		/// Is the pointer (or reference) on top of the stack non-null.
		/// </summary>
		internal void SimulatePointerNonNull()
		{
			IRType tt = this.m_evalstack.PeekType();

			if(tt is IRPtrType)
			{
				PtrValue pv = this.m_evalstack.PopPointerNoTypeConvert();

				int nn = !pv.IsNullPtr ? 1 : 0;
				NumericValue nv = NumericValue.MakeSignedValueOfType(nn, GlobalInterpreterState.TProg.TypeTable.Int32Type);
				this.m_evalstack.PushNumericEvalEntry(nv);
			}
			else
			{
				ReferenceValue rv = this.m_evalstack.PopReference();

				int nn = (!rv.IsNullReference) ? 1 : 0;
				NumericValue nv = NumericValue.MakeSignedValueOfType(nn, GlobalInterpreterState.TProg.TypeTable.Int32Type);
				this.m_evalstack.PushNumericEvalEntry(nv);
			}
		}

		/// <summary>
		/// Is the reciver value in a vcall non-null.
		/// </summary>
		internal bool IsVCallNonNull(int rcvrpos)
		{
			IRType tt = this.m_evalstack.PeekTypeK(rcvrpos);

			if(tt is IRPtrType)
				return !this.m_evalstack.PeekPtrK(rcvrpos).IsNullPtr;
			else if(tt is IRReferenceType)
				return !this.m_evalstack.PeekReferenceK(rcvrpos).IsNullReference;
			else
				return true;
		}

		//////////////
		//Type Operations

		/// <summary>
		/// Box the valuetype on the top of the stack.
		/// </summary>
		internal void SimulateBox(IRValueType typetobox)
		{
			IRBoxedType boxedty = GlobalInterpreterState.TProg.TypeTable.LookupBoxedTypeFor(typetobox);
			IRPtrType ptrtoboxedty = GlobalInterpreterState.TProg.TypeTable.LookupPointerTypeFor(boxedty);
			IRReferenceType reftoboxedty = GlobalInterpreterState.TProg.TypeTable.LookupReferenceTypeFor(typetobox);

			CObject bxn = MemoryState.AllocateStdHeapObject(boxedty);
			IRMemberField boxf = boxedty.BoxedValueField;
			IRBasicAccessPath boxbap = GlobalInterpreterState.TProg.GetAccessPathForSingleField(boxf);

			ReferenceValue refv = new ReferenceValue(bxn.Address, boxbap, -1, reftoboxedty);

			if(typetobox is IRPrimitiveNumericType || typetobox is IREnumType)
			{
				NumericValue nv = this.m_evalstack.PopNumericValueAsType(typetobox);

				this.m_evalstack.PushPointerEvalEntry(new PtrValue(bxn.Address, ptrtoboxedty));
				this.m_evalstack.PushReferenceEvalEntry(refv);
				this.m_evalstack.PushNumericEvalEntry(nv);
			}
			else
			{
				IRStructType svtype = (IRStructType)typetobox;
				CompositeValueEntry[] cve = this.m_evalstack.PopStruct();

				this.m_evalstack.PushPointerEvalEntry(new PtrValue(bxn.Address, ptrtoboxedty));
				this.m_evalstack.PushReferenceEvalEntry(refv);
				this.m_evalstack.PushStructEvalEntry(svtype, cve);
			}

			this.SimulateDeRefIndirectWrite();
		}

		/// <summary>
		/// Unbox the boxed object on the offset from the stack top (e.g. get a reference to the boxed contents).
		/// </summary>
		internal void SimulateUnBox(IRValueType typetounbox, int sloc)
		{
			Debug.Assert(this.m_evalstack.PeekTypeK(sloc) is IRPtrType);
			this.m_evalstack.DupPositionToTop(sloc);

			PtrValue pv = this.m_evalstack.PopPointerNoTypeConvert();
			if(pv.IsNullPtr)
				throw new InterpRuntimeException("Null Ptr on UnBox!!");

			IRBoxedType boxetype = GlobalInterpreterState.TProg.TypeTable.LookupBoxedTypeFor(typetounbox);
			IRMemberField boxfield = boxetype.BoxedValueField;
			IRBasicAccessPath bap = GlobalInterpreterState.TProg.GetAccessPathForSingleField(boxfield);

			ReferenceValue rv = new ReferenceValue(pv.TargetAddress, bap, -1, GlobalInterpreterState.TProg.TypeTable.LookupReferenceTypeFor(typetounbox));
			this.m_evalstack.PushReferenceEvalEntry(rv);

			this.m_evalstack.RotateTopToPosition(sloc);
		}

		/// <summary>
		/// Cast with throw to given type.
		/// </summary>
		internal void SimulateCast(IRPtrType castto)
		{
			bool isinst = this.CheckIsInstOfStackTop(castto, true);
			if(!isinst)
				throw new InterpRuntimeException("Invalid Cast!");
		}

		/// <summary>
		/// Cast without throw to given type (null is pushed if not possible otherwise the recast pointer is).
		/// </summary>
		internal void SimulateIsInst(IRPtrType instof)
		{
			this.CheckIsInstOfStackTop(instof, false);
		}

		/// <summary>
		/// Perform the constraint operation on the given stack position.
		/// </summary>
		internal void SimulateConstrain(IRType constrinto, int pos)
		{
			this.m_evalstack.DupPositionToTop(pos);

			if(constrinto is IRReferenceType)
			{ ;}
			else
			{
				Debug.Assert(constrinto is IRPtrType);

				IRType atype = ((IRPtrType)constrinto).PtrTargetType;
				if(atype is IRBoxedType)
				{
					this.SimulateDeRefIndirectRead();
					this.SimulateBox(((IRBoxedType)atype).BoxedTypeValue);
				}
				else
				{
					this.SimulateDeRefIndirectRead();
				}
			}

			this.m_evalstack.RotateTopToPosition(pos);
		}

		/// <summary>
		/// return true if the top value on the stack is a subtype of the given derefable (treats a null pointer as a subtype if 
		/// <c>nulloksubtype</c> is true otherwise null is not a subtype of any type).
		/// </summary>
		private bool CheckIsInstOfStackTop(IRPtrType instof, bool nulloksubtype)
		{
			PtrValue pv = this.m_evalstack.PopPointerNoTypeConvert();
			if(pv.IsNullPtr)
			{
				PtrValue npv = PtrValue.MakeNullPtr(GlobalInterpreterState.TProg.TypeTable.NullType);
				this.m_evalstack.PushPointerEvalEntry(npv);
				return nulloksubtype;
			}

			CObject ploc = ResolvePointerTarget(pv);
			ploc.MarkRTTIUsed();

			bool ok = instof.PtrTargetType.TypeDescription.AllSubTypes.Contains(ploc.LocationType);
			if(ok)
			{
				PtrValue okpv = new PtrValue(pv.TargetAddress, instof);
				this.m_evalstack.PushPointerEvalEntry(okpv);
			}
			else
			{
				PtrValue npv = PtrValue.MakeNullPtr(instof);
				this.m_evalstack.PushPointerEvalEntry(npv);
			}

			return ok;
		}

		//////////////
		//Misc Operations

		/// <summary>
		/// Pop the top of the stack.
		/// </summary>
		internal void SimulatePop()
		{
			this.m_evalstack.DiscardPop();
		}

		/// <summary>
		/// Duplicate the element on the top of the stack.
		/// </summary>
		internal void SimulateDup()
		{
			this.m_evalstack.Dup();
		}

		/// <summary>
		///Push the null literal on the stack.
		/// </summary>
		internal void SimulatePushNull()
		{
			PtrValue pv = PtrValue.MakeNullPtr(GlobalInterpreterState.TProg.TypeTable.NullType);
			this.m_evalstack.PushPointerEvalEntry(pv);
		}

		/// <summary>
		/// Push the given int literal on the stack.
		/// </summary>
		internal void SimulatePushInt(IRSignedIntegerType ptype, long val)
		{
			NumericValue nv = NumericValue.MakeSignedValueOfType(val, ptype);
			this.m_evalstack.PushNumericEvalEntry(nv);
		}

		/// <summary>
		/// Push the given float literal on the stack.
		/// </summary>
		internal void SimulatePushFloat(double fval)
		{
			NumericValue nv = NumericValue.MakeFloatValueOfType(fval, GlobalInterpreterState.TProg.TypeTable.Float64Type);
			this.m_evalstack.PushNumericEvalEntry(nv);
		}

		/// <summary>
		/// Push the given string literal on the stack.
		/// </summary>
		internal void SimulatePushString(string litval)
		{
			this.PushStringPtrFromCSString_Helper(litval);
		}

		////////
		//Support for calls and exceptions

		/// <summary>
		/// Assert that an argument parameter var is of a specific type.
		/// </summary>
		internal void SetArgType(IRType tt, int argpos)
		{
			this.m_evalstack.SetArgType(tt, argpos);
		}

		/// <summary>
		/// Return the type of the eval stack that the call is being invoked on.
		/// </summary>
		internal IRType GetTargetEvalStackRcvrType(int rcvrpos)
		{
			return this.m_evalstack.PeekTypeK(rcvrpos);
		}

		/// <summary>
		/// Return the resolved method target for a virtual call.
		/// </summary>
		internal IRClassType GetTargetCallClassForName(int rcvrpos)
		{
			PtrValue pv = this.m_evalstack.PeekPtrK(rcvrpos);
			
			CObject obj = ResolvePointerTarget(pv);

			obj.MarkRTTIUsed();
			return (IRClassType)obj.LocationType;
		}

		/// <summary>
		/// Take a reference to a freshly allocated object on top of the stack and rotate it into the correct position to be 
		/// the reciver argument on stack.
		/// </summary>
		internal void RotateBlankAllocToRecvrPosition(int rcvrpos)
		{
			this.m_evalstack.RotateTopToReciever(rcvrpos);
		}

		/// <summary>
		/// Take the return value from this and push it onto the caller frame.
		/// </summary>
		internal void PushReturnOntoCallerStack(LocalCallFrame callerframe, IRType rettype)
		{
			this.m_evalstack.MoveReturnValue(callerframe.m_evalstack, rettype);
		}

		/// <summary>
		/// Pop the top top arg on the stack into the appropriate local variable
		/// </summary>
		internal void PopStackArgIntoLocalName(IRVarName lclv, IRType lcltype)
		{
			CHomeLocation newloc = MemoryState.AllocateHomeLocation(lclv, lcltype);
			this.m_localvarmap.Add(lclv, newloc);

			this.SimulateStoreToLocal(lclv);
		}

		/// <summary>
		/// Move the top <c>argount</c> elements from <c>callerframe</c> into this evalstack and then clear them from <c>callerframe</c>
		/// </summary>
		internal void MoveCallArgsToThis(LocalCallFrame callerframe, int argcount)
		{
			this.m_evalstack.MoveCallArgsToThis(callerframe.m_evalstack, argcount);
		}

		/// <summary>
		/// When we return from the initialization that is implicitly called we want to push the this reference as the return value.
		/// </summary>
		internal void PopInitializedRefBackToStackReturn(IRType alloctype)
		{
			IRVarName retv = GlobalInterpreterState.TProg.NameTable.LookupLocalVarName("this");
			this.SimulateLoadFromLocal(retv);

			if(alloctype is IRStructType)
				this.SimulateDeRefIndirectRead();
		}

		/// <summary>
		/// If we have a call through a lambda get the possible set of invocation targets from it.
		/// </summary>
		internal IRInvokeIdentity GetLambdaInvokeTarget(int rcvrpos)
		{
			this.m_evalstack.DupPositionToTop(rcvrpos);
			PtrValue dpv = this.m_evalstack.PopPointerNoTypeConvert();
			CDelegate ln = (CDelegate)ResolvePointerTarget(dpv);
			ln.MarkRTTIUsed();

			return ln.m_invoke;
		}

		/// <summary>
		/// If we have a call through a lambda this will pop the lambda off the stack as needed.
		/// </summary>
		internal void PopOrConvertLambdaAsNeeded(int rcvrpos, IRInvokeIdentity iidtc)
		{
			if(iidtc.InvSig is IRStaticInvoke)
				this.m_evalstack.DiscardRcvrPosition(rcvrpos);
			else
			{
				this.m_evalstack.DupPositionToTop(rcvrpos);

				PtrValue lv = this.m_evalstack.PopPointerNoTypeConvert();
				CDelegate tn = (CDelegate)ResolvePointerTarget(lv);
				CObject lpv = ResolvePointerTarget(tn.LoadObjectArgPointer());

				IRPtrType rcvrtype = GlobalInterpreterState.TProg.TypeTable.LookupPointerTypeFor((IRClassType)iidtc.DefInClass);
				this.m_evalstack.PushPointerEvalEntry(new PtrValue(lpv.Address, rcvrtype));

				this.m_evalstack.RotateTopToReciever(rcvrpos);
			}
		}
	}
}
